#ifndef __SDAT_H__
#define __SDAT_H__

#include "ndstypes.h"		// This header is from libnds
#include "ndsexcept.h"
#include <iostream>
#include <vector>

#define SAFE_DELETE(obj) if(obj) { delete obj; }

namespace nds {
	#pragma pack(push, 1)
	typedef struct NDSHeader {	//This structure is from libnds
		char gameTitle[12];
		char gameCode[4];
		char makercode[2];
		u8 unitCode;
		u8 deviceType;		// type of device in the game card
		u8 deviceSize;		// device capacity (1<<n Mbit)
		u8 reserved1[9];
		u8 romversion;
		u8 flags;			// auto-boot flag

		u32 arm9romOffset;
		u32 arm9executeAddress;
		u32 arm9destination;
		u32 arm9binarySize;

		u32 arm7romOffset;
		u32 arm7executeAddress;
		u32 arm7destination;
		u32 arm7binarySize;

		u32 filenameOffset;
		u32 filenameSize;
		u32 fatOffset;
		u32 fatSize;

		u32 arm9overlaySource;
		u32 arm9overlaySize;
		u32 arm7overlaySource;
		u32 arm7overlaySize;

		u32 cardControl13;  // used in modes 1 and 3
		u32 cardControlBF;  // used in mode 2
		u32 bannerOffset;

		u16 secureCRC16;

		u16 readTimeout;

		u32 unknownRAM1;
		u32 unknownRAM2;

		u32 bfPrime1;
		u32 bfPrime2;
		u32 romSize;

		u32 headerSize;
		u32 zeros88[14];
		u8 gbaLogo[156];
		u16 logoCRC16;
		u16 headerCRC16;

		u32 debugRomSource;
		u32 debugRomSize;
		u32 debugRomDestination;
		u32 offset_0x16C;

		u8 zero[0x90];
	} NDSHeader;

	typedef struct NDSGenHdr {
		char magicID[4];	// Identifies the file format.
		u32 constant;		// Always (0xFFFE0001)
		u32 sectionSize;	// Size of this section, including the header.
		u16 headerSize;		// Size of this header. (Should always equal 0x10)
		u16 numSections;	// The number of sub-sections in this section. 
	} NDSGenHdr;
    
	typedef struct NDSSDAT {
		NDSGenHdr hdr;		// The generic header
    
		u32 ofsSYMB;		// Offset to SYMB block
		u32 sizSYMB;		// Size of SYMB block
    
		u32 ofsINFO;		// Offset to INFO block
		u32 sizINFO;		// Size of INFO block
    
		u32 ofsFAT;			// Offset to FAT block
		u32 sizFAT;			// Size of FAT block
    
	    u32 ofsFILE;		// Offset to FILE block
		u32 sizFILE;		// Size of FILE block
	} NDSSDAT;
    
	typedef struct SDATSYMB {
		char type[4];		// 'SYMB'
		u32 nSize;			// Size of this block
		u32 nRecOffset[8];	// Offset of Records
		u8  reserved[24];	// Unused
	} SDATSYMB;
    
	typedef struct SDATINFO {
		char type[4];		// 'INFO'
		u32 nSize;			// Size of this block
		u32 nRecOffset[8];	// Offset of records
	    u8  reserved[24];	// Unused
	} SDATINFO;
    
	typedef struct SDATFATREC {
		u32 nOffset;		// Offset of the sound file
		u32 nSize;			// Size of the Sound file
		u32 reserved[2];	// Unused
	} SDATFATREC;
    
	typedef struct SDATFAT {
		char type[4];		// 'FAT '
		u32 nSize;			// Size of FAT
 		u32 nCount;			// Number of records
		SDATFATREC* Rec;	// Arrays of records
	} SDATFAT;  
    
	typedef struct SDATINFOREC {
		u32 nCount;			// No of entries in this record
		u32* nEntryOffset;	// Array of offsets of each entry
	} SDATINFOREC;
    
	typedef struct SDATSYMBREC {
		u32 nCount;			// No of entries in this record
		u32* nEntryOffset;	// Array of offsets of each entry
	} SDATSYMBREC;
    

	typedef struct SDATINFOSSEQ {
		u16 fileID;			// For accessing this file
		u16 unknown;		// Unknown
		u16 bnk;			// Associated BANK
		u8  vol;			// Volume
		u8  cpr;
		u8  ppr;
		u8  ply;
		u8  unknown2[2];	// Unknown	
	} SDATINFOSSEQ;
    
	typedef struct SDATINFOSBNK {
		u16 fileID;			// For accessing this file
		u16 unknown;		// Unknown
		u16 wa[4];			// Associated WAVEARC. 0xffff if not in use
	} SDATINFOSBNK;
    
	typedef struct SDATINFOSWAR {
		u16 fileID;			// For accessing this file
		u16 unknown;		// Unknown
	} SDATINFOSWAR;
    
	typedef struct SDATSSEQ {
		char* symbol;		// The filename of this file
		SDATINFOSSEQ info;	// Holds file info
		SDATFATREC rec;		// FAT record
		u8* data;			// File data in memory
	} SDATSSEQ;
    
	typedef struct SDATSBNK {
		char* symbol;		// The filename of this file
		SDATINFOSBNK info;	// Holds file info
		SDATFATREC rec;		// FAT record
		u8* data;			// File data in memory
	} SDATSBNK;
    
	typedef struct SDATSWAR {
		char* symbol;		// The filename of this file
		SDATINFOSWAR info;	// Holds file info
		SDATFATREC rec;		// FAT record
		u8* data;			// File data in memory
	} SDATSWAR;
	#pragma pack(pop)
    
    
    class sdat {
    private:
        NDSSDAT header;
        u32 offsetInRom;
        void loadSDAT(std::ifstream& is, std::streampos offset);
        
    protected:
        std::vector<SDATSSEQ> sseq;
        std::vector<SDATSBNK> sbnk;
        std::vector<SDATSWAR> swar;
        
    public:
        sdat();
        ~sdat();
        
        void loadFromRom(std::string romfile);        // Scans through an NDS ROM file looking for "SDAT" and loads the internal data
        void loadFromFile(std::string sdatfile);      // Loads an .SDAT file pre-extracted from an NDS ROM
    };

}; // namespace nds

#endif
